﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace DGen
{
    /// <summary>
    /// Static helper class for dealing with Text in a variety of ways. 
    /// </summary>
    public static partial class DText
    {
        /// <summary>
        /// Returns size in formatted string bytes, mbytes, etc.
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string FormatBytes(long bytes)
        {
            const int scale = 1024;
            string[] orders = new string[] { "GB", "MB", "KB", "Bytes" };
            long max = (long)Math.Pow(scale, orders.Length - 1);
            foreach (string order in orders)
            {
                if (bytes > max)
                    return string.Format("{0:##.##} {1}", decimal.Divide(bytes, max), order);
                max /= scale;
            }
            return "0 Bytes";
        }
        /// <summary>
        /// Iterates thru an entire string, and sets the first letter of 
        /// each word to uppercase, and all ensuing letters to lowercase
        /// </summary>
        /// <param name="stream">The string to alter the case of</param>
        /// <returns>
        /// Same string w/uppercase initial letters and others as lowercase
        /// </returns>
        public static string MixCase(string stream)
        {
            try
            {
                string newString = string.Empty;
                string character = string.Empty;
                string preceder = string.Empty;
                for (int i = 0; i < stream.Length; i++)
                {
                    character = stream.Substring(i, 1);
                    if (i > 0)
                    {
                        //look at the character immediately before current
                        preceder = stream.Substring(i - 1, 1);
                        //remove white space character from predecessor
                        if (preceder.Trim() == string.Empty)
                            //the preceding character WAS white space, so
                            //we'll change the current character to UPPER
                            character = character.ToUpper();
                        else
                            //the preceding character was NOT white space,
                            //we'll force the current character to LOWER
                            character = character.ToLower();
                    }
                    else
                        //index is 0, thus we are at the first character
                        character = character.ToUpper();
                    //add the altered character to the new string:
                    newString += character;
                }
                return newString;
            }
            catch (Exception ex)
            {
                DBug.ErrorTools.ProcessError(ex);
                return null;
            }
        }
        /// <summary>
        /// Another Clean Value overload.
        /// </summary>
        /// <param name="currentDType"></param>
        /// <param name="colValue"></param>
        /// <returns></returns>
        public static string CleanValue(DataTypes currentDType, string colValue)
        {
            if (currentDType == DataTypes.integer || currentDType == DataTypes.numeric)
            {
                bool allNum = true;
                foreach (char c in colValue.ToCharArray())
                {
                    if ((Char.IsNumber(c)==false && Char.IsPunctuation(c)==false) || c==',')
                    {
                        allNum = false;
                        break;
                    }
                }
                if (allNum == false)
                {
                    colValue = DText.CleanNumeric(colValue);
                }
            }
            return colValue;
        }
        /// <summary>
        /// Iterates thru a string, and removes anything set to clean.
        /// Except---Does NOT remove anything in exceptionsToAllow
        /// </summary>
        /// <param name="stream">The string to clean</param>
        /// <param name="cleanWhiteSpace"></param>
        /// <param name="cleanDigits"></param>
        /// <param name="cleanLetters"></param>
        /// <param name="exceptionsToAllow"></param>
        /// <returns>
        /// The same string, missing all elements that were set to clean
        /// (except when a character was listed in exceptionsToAllow)
        /// </returns>
        public static string Clean(string stream, bool cleanWhiteSpace,
                                   bool cleanDigits, bool cleanLetters, string exceptionsToAllow)
        {
            try
            {
                string newString = string.Empty;
                string character = string.Empty;
                string blessed = string.Empty;
                if (!cleanDigits)
                    blessed += m_Digits;
                if (!cleanLetters)
                    blessed += m_Letters;
                blessed += exceptionsToAllow;
                //we set the comparison string to lower
                //and will compare each character's lower case version
                //against the comparison string, without
                //altering the original case of the character
                blessed = blessed.ToLower();
                for (int i = 0; i < stream.Length; i++)
                {
                    character = stream.Substring(i, 1);
                    if (blessed.Contains(character.ToLower()))
                        //add the altered character to the new string:
                        newString += character;
                    else if (character.Trim() == string.Empty &&
                             !cleanWhiteSpace)
                        newString += character;
                }
                return newString;
            }
            catch (Exception ex)
            {
                DBug.ErrorTools.ProcessError(ex);
                return null;
            }
        }
        /// <summary>
        /// Removes all apostrophes not prefixed by another apostrophe or a backslash.
        /// </summary>
        /// <param name="tmpHolder"></param>
        /// <returns></returns>
        public static string RemoveUnescapedApostrophes(string tmpHolder)
        {
            tmpHolder = tmpHolder.Replace(@"\'", "ZXA111");
            tmpHolder = tmpHolder.Replace(@"''", "ZXA112");
            tmpHolder = tmpHolder.Replace("'", "");
            tmpHolder = tmpHolder.Replace("ZXA111", @"\'");
            tmpHolder = tmpHolder.Replace("ZXA112", @"''");
            return tmpHolder;
        }
        /// <summary>
        /// From some website. Emulates T-SQL Left function.
        /// </summary>
        /// <param name="text"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public static string Left(string text, int length)
        {
            if (length < 0)
                throw new ArgumentOutOfRangeException("length", length, "length must be > 0");
            else if (length == 0 || text.Length == 0)
                return "";
            else if (text.Length <= length)
                return text;
            else
                return text.Substring(0, length);
        }
        /// <summary>
        /// Removes all whitespaces, tabs, newlines, etc from input string.
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public static string RemoveWhiteSpace(string x)
        {
            char[] foo = x.Trim().ToCharArray();
            string tmpColName = "";
            foreach (char letter in foo)
            {
                if (Char.IsWhiteSpace(letter))
                {
                }
                else
                {
                    tmpColName += letter;
                }
            }
            return tmpColName;
        }
        /// <summary>
        /// Removes speech mark but only where it straddles/surrounds a field.
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public static string RemoveDoubleQuotes(string x)
        {
            if (x != null)
            {
                if (x.Length > 0)
                {
                    string quote = "\"";
                    string y = String.Empty;
                    if (x.Substring(0, 1) == quote || x.Length > 0 && x.Substring(x.Length - 1, 1) == quote)
                    {
                        y = x.Trim('"');
                    }
                    else
                    {
                        y = x;
                    }
                    return y;
                }
                else
                {
                    return x;
                }
            }
            return " ";
        }
        /// <summary>
        /// Removes apostrophes completely (does not escape anything). 
        /// </summary>
        /// <param name="inputString"></param>
        /// <returns></returns>
        public static string RemoveApostrophes(string inputString)
        {
            return inputString.Replace("'", "");
        }
        /// <summary>
        /// makes a string "suitable" for use as a t-sql column name. 
        /// Removes spaces, slashes, dashes, hashes, etc. 
        /// </summary>
        /// <param name="columnName"></param>
        /// <returns></returns>
        public static string FixColumnHeader(string columnName)
        {
            var undesirableChars = new char[10];
            undesirableChars[0] = '/';
            undesirableChars[1] = '-';
            undesirableChars[2] = '[';
            undesirableChars[3] = ']';
            undesirableChars[4] = '#';
            undesirableChars[5] = '"';
            undesirableChars[6] = '\t';
            undesirableChars[7] = '\n';
            undesirableChars[7] = '\r';
            foreach (char udc in undesirableChars)
            {
                columnName = columnName.Replace(udc.ToString(), string.Empty);
            }
            columnName = columnName.Substring(0, Math.Min(columnName.Length, 35));
            columnName =  columnName.Replace(" ","_") ;
            return columnName;
        }
        /// <summary>
        /// removes commas, spaces, USD and GBP sterling signs from text.
        /// </summary>
        /// <param name="tmpHolder"></param>
        /// <param name="alternate"></param>
        /// <param name="redundant"></param>
        /// <returns></returns>
        public static string CleanNumeric(string tmpHolder, bool alternate, bool redundant)
        {
            string b = String.Empty;
            return tmpHolder.Replace(",", b).Replace("£", b).Replace("$", b).Replace(" ", b).Replace("'", b);
        }
        /// <summary>
        /// removes commas, spaces, USD and GBP sterling signs from text.
        /// </summary>
        /// <param name="tmpHolder"></param>
        /// <returns></returns>
        public static string CleanNumeric(string tmpHolder)
        {
            
            char[] badChars = new char[] { ',', '£', '$', '%', ' ', '\'', ':', ';', '^', '&', '*', '"' , ')','(','+','-'};
            foreach (char udc in badChars)
            {
                tmpHolder = tmpHolder.Replace(udc.ToString(),String.Empty);
            }
            return tmpHolder;
        }
        /// <summary>
        /// overload using regex - more thorough but much slower.
        /// </summary>
        /// <param name="tmpHolder"></param>
        /// <param name="fullWipe"></param>
        /// <returns></returns>
        public static string CleanNumeric(string tmpHolder, bool fullWipe)
        {
            string pattern = @"[^\-\.0-9e]|\-$|\.$";
            string replacement = String.Empty;
            return System.Text.RegularExpressions.Regex.Replace(tmpHolder, pattern, replacement);
        }
        /// <summary>
        /// overload using enumerating approach.
        /// </summary>
        /// <param name="tmpHolder"></param>
        /// <param name="dummyParameter"></param>
        /// <returns></returns>
        public static string CleanNumeric(string tmpHolder, int dummyParameter)
        {
            List<char> newChars = new List<char>();
            foreach (char c in tmpHolder.ToCharArray())
            {
                if (Char.IsNumber(c))
                {
                    newChars.Add(c);
                }
            }
            return newChars.ToArray().ToString();
        }
        /*
         * 
string replacement = String.Empty;
         * */
        /// <summary>
        ///
        /// </summary>
        /// <param name="columnString"></param>
        /// <returns></returns>
        public static string CleanValue(string columnString)
        {
            return RemoveDoubleQuotes(columnString).Trim();
        }
        /// <summary>
        /// Removes pound signs, etc from number strings. Overloaded version removes whitespace too.
        /// </summary>
        /// <param name="columnString">Number string to be cleaned.</param>
        /// <param name="reallyClean">Either true or false, it makes no difference/</param>
        /// <returns></returns>
        public static string CleanValue(string columnString, bool reallyClean)
        {
            columnString = RemoveDoubleQuotes(columnString);
            columnString = columnString.Trim();
            if (DText.IsScientificNotation(columnString))
            {
                columnString = DText.ConvertScientificNotationToDouble(columnString);
            }
            return Regex.Replace(columnString, @"[,|£+]", String.Empty);
        }
        /// <summary>
        /// Removes pound sounds, commas and spaces form numbers.
        /// </summary>
        /// <param name="columnString"></param>
        /// <param name="reallyClean"></param>
        /// <param name="removeSpaces"></param>
        /// <returns></returns>
        public static string CleanValue(string columnString, bool reallyClean, bool removeSpaces)
        {
            columnString = RemoveDoubleQuotes(columnString);
            columnString = columnString.Trim();
            if (DText.IsScientificNotation(columnString))
            {
                columnString = DText.ConvertScientificNotationToDouble(columnString);
            }
            return Regex.Replace(columnString, @"[,|£|\s+]", String.Empty);
        }
        /// <summary>
        /// Removes NULL from tab separated fields that you might find from SQL Server 2005 Mgt Studio output.
        /// Note : Is only removing the word NULL - not empty/void/vacant cells
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string RemoveNulls(string input)
        {
            string s = Regex.Replace(input, "NULL", " ");
            return s;
        }
        /// <summary>
        /// Simplistic - definitely not definitive post code format checker.
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static bool IsValidPostCode(string input)
        {
            input = input.Trim().ToUpper();
            string pattern = @"^(GIR|[A-Z]\d[A-Z\d]??|[A-Z]{2}\d[A-Z\d]??)[ ]??(\d[A-Z]{2})$";
            return Regex.IsMatch(input, pattern);
        }
        /// <summary>
        /// Returns first post code from string.
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string GetPostCode(string input)
        {
            input = input.Trim().ToUpper();
            string pattern = @"(GIR|[A-Z]\d[A-Z\d]??|[A-Z]{2}\d[A-Z\d]??)[ ]??(\d[A-Z]{2})";
            if (Regex.IsMatch(input, pattern))
            {
                var m = Regex.Matches(input, pattern);
                return m[0].Value;
            }
            else return string.Empty;
        }
        /// <summary>
        /// Returns first half of post code found.
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string GetPostStub(string input)
        {
            input = input.Trim().ToUpper();
            string pattern = @"([A-Z][0-9]|[A-Z][0-9]{2}|[A-Z]{2}[0-9]|[A-Z]{2}[0-9]{2})(\s|$)";
            if (Regex.IsMatch(input, pattern))
            {
                var m = Regex.Matches(input, pattern);
                return m[0].Value;
            }
            else return string.Empty;
        }
        /// <summary>
        /// Get's first instance of postal district in the string.
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string GetDistrict(string input)
        {
            input = input.Trim().ToUpper();
            string pattern = @"(DUNDEE|READING|DORCHESTER|NEWCASTLE UPON TYNE|PLYMOUTH|TAUNTON|TELFORD|LIVERPOOL|LANCASTER|BRADFORD|DURHAM|CANTERBURY|LONDON|BRISTOL|ABERDEEN|HEMEL HEMPSTEAD|ST. ALBANS|SALISBURY|COVENTRY|LEICESTER|MOTHERWELL|TORQUAY|COLCHESTER|UVBRIDGE|STEVENAGE|MEDWAY|SHETLAND ISLES|WALSALL|HALIFAX|LLANDUDNO|SOUTHAMPTON|SHREWSBURY|WORCESTER|TEESIDE|BRIGHTON|DUMFRIES|HARROGATE|SUNDERLAND|CROYDON|CHELMSFORD|WARRINGTON|TWICKENHAM|GLOUCESTER|SUTTON|GUILDFORD|WIGAN|CARDIFF|SCOTTISH ISLANDS|DERBY|EXETER|KILMARNOCK|DARTFORD|TWEED|SWANSEA|BLACKPOOL|LLANDRINDOD WELLS|ENFIELD|HUDDERSFIELD|KIRKCALDY|STOCKPORT|REDHILL|PORTSMOUTH|CARLISLE|BLACKBURN|BELFAST|LINCOLN|SHEFFIELD|WOLVERHAMPTON|NOTTINGHAM|ILFORD|LUTON|BIRMINGHAM|SLOUGH|GLASGOW|INVERNESS|CAMBRIDGE|NEWPORT|DUDLEY|WATFORD|OLDHAM|NORWICH|SOUTHEND ON SEA|BATH|DONCASTER|STOKE ON TRENT|EDINBURGH|MILTON KEYNES|IPSWICH|DARLINGTON|HEREFORD|PRESTON|TONBRIDGE|OXFORD|CREWE|HULL|KINGSTON UPON THAMES|MANCHESTER|TRURO|YORK|ROMFORD)";
            if (Regex.IsMatch(input, pattern))
            {
                var m = Regex.Matches(input, pattern);
                return m[0].Value;
            }
            else return string.Empty;
        }
        /// <summary>
        /// Returns only alphabetic characters
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string JustLetters(string input)
        {
            input = input.Trim().ToUpper();
            string pattern = @"[^A-Z\s]*";
            string result = Regex.Replace(input, pattern, string.Empty);
            return result;
        }
        /// <summary>
        /// returns only integers from string
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string JustNumbers(string input)
        {
            input = input.Trim().ToUpper();
            string pattern = "[^0-9]*";
            string result = Regex.Replace(input,pattern,string.Empty);
            return result;
        }
        /// <summary>
        /// Based on T-SQL function of same name. Repeats a string n number of times.
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="repeat"></param>
        /// <returns></returns>
        public static string Replicate(string expression, int repeat)
        {
            string mString = string.Empty;
            for (int i = 0; i < repeat; i++)
            {
                mString += expression;
            }
            return mString;
        }
    }
}
